/*
 * row.h
 *
 * Copyright (c) 2009, Eugen Stoian <stoian.e@gmail.com>
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
 * http://www.fsf.org/licensing/licenses/lgpl.txt
 */


#ifndef ROW_H_
#define ROW_H_
#ifdef _OPENMP
#include <omp.h>
#endif
#include <memalloc.h>
#include <core.h>
#include <pxxdefs.h>
#include <cstring>
#include <cmath>

namespace pxx
{
template<typename T>
class matrix;

template <typename T>
class vector
{
protected:
	void allocate();
	void initialize(int count);
	void free();
public:
	vector(int n);
	vector(vector const &);
	vector& operator=(vector const &);
#ifdef __GXX_EXPERIMENTAL_CXX0X__
	vector(vector &&);
	vector& operator=(vector &&);
#endif
	virtual ~vector();
	/*!
	 * \fn operator()(int i) const
	 * \brief Function call operator
	 * \return the value of the \b i-th coordinate of the vector
	 */
	inline T operator()(int i) const {
		return _data[i];
	}
	/*!
	 * \fn operator()(int i)
	 * \brief Function call operator
	 * \return a reference to the \b i-th coordinate of the vector
	 */
	inline T& operator()(int i) {
		return _data[i];
	}

	/*!
	 * \fn operator+(vector const & v) const
	 * \param v a const reference to a vector object of the same size like current object
	 * \brief Addition operator
	 * \return A vector object equal with the sum of the vectors
	 */
	inline vector operator+(vector const & v) const{
		return add(v);
	}

	/*!
	 * \fn operator-(vector const & v) const
	 * \param v a const reference to a vector object of the same size like current object
	 * \brief Substraction operator
	 * \return a vector object equal with the difference of the vectors
	 */
	inline vector operator-(vector const & v) const{
		return sub(v);
	}

	/*!
	 * \fn operator*(vector const & v) const
	 * \param v a const reference to a vector object of the same size like current object
	 * \brief Multiplication operator
	 * \return a single precision float number equal with the value of the dot product of the vectors
	 */
	inline T operator*(vector const & v) const{
		return dotProduct(v);
	}

	/*!
	 * \fn operator*(T f) const
	 * \param f a single precision float number
	 * \brief Multiplication operator
	 * \return a  vector object equal with the current vector multiplied with the scalar d
	 */
	inline vector operator*(T f) const{
		return muls(f);
	}

	/*!
	 * \fn length() const
	 * \brief The vector length
	 * \return the value of the vector norm
	 * \sa norm(), magnitude()
	 */
	inline T length() const {
		return norm();
	}

	/*!
	 * \fn magnitude() const
	 * \brief The vector magnitude
	 * \return the value of the vector norm
	 * \sa length(), norm()
	 */
	inline T magnitude() const {
		return norm();
	}

	T norm() const;

	vector add(vector const &) const;

	vector sub(vector const &) const;


	T dotProduct(vector const &) const;

	vector muls(T) const;

	friend class matrix<T>;

	inline bool isSized() const{
		return _count;
	}
	inline bool isAllocated() const{
			return  _data;
	}
	inline int count() {
		return _count;
	}
protected:
	T* _data;
	int _count;
};

template <typename T>
void vector<T>::allocate(){
			_data = (T*) pxx::memalloc(_count * sizeof(T));
}

template <typename T>
void vector<T>::initialize(int count){
	_count = count;
	if(isSized())
		allocate();
	else
		_count = 0;
}

template <typename T>
void vector<T>::free(){
	if(_data)
			pxx::memfree(_data);
}


template <typename T>
vector<T>::vector(int n):
	_data(0), _count(n){
	if (isSized()) {
		allocate();
		for (int i = 0; i < _count; ++i) {
			_data[i] = 0;
		}
	}
}

template <typename T>
vector<T>::vector(vector const & v) :
	_data(v._data), _count(v._count) {
	if (isSized()) {
		allocate();
		memcpy(_data,v._data,_count*sizeof(T*));
	}
}

template <typename T>
vector<T>& vector<T>::operator=(vector const & v)
{
	if (this != &v) {
		if(isAllocated()){
			if(_count!=v._count)
				throw 0;
			memcpy(_data,v._data,_count*sizeof(T*));
		}
		else {
			if(v.isAllocated()){
				initialize(v._count);
				memcpy(_data,v._data,_count*sizeof(T*));
			}
		}
	}
	return *this;
}

#ifdef __GXX_EXPERIMENTAL_CXX0X__
template <typename T>
vector<T>::vector(vector && v):
	_data(v._data),_count(v._count) {
	v._data = 0;
}

template <typename T>
vector<T>& vector<T>::operator=(vector && v)
{
	if(isAllocated()){
		if(_count!=v._count)
			throw 0;
		free();
	}
	_count = v._count;
	_data = v._data;
	v._data = 0;
	return *this;
}
#endif

template <typename T>
vector<T>::~vector()
{
	free();
}

template <typename T>
T vector<T>::norm() const {
	return sqrt(dotProduct(*this));
}

template <typename T>
vector<T> vector<T>::add(vector const & v) const{
	vector result(_count);
	if(_count!=v._count) throw 0;
	pxx::core::VAddV(_count,_data,v._data,result._data);
	return result;
}

template <typename T>
vector<T> vector<T>::sub(vector const & v) const{
	vector result(_count);
	if(_count!=v._count) throw 0;
	pxx::core::VSubV(_count,_data,v._data,result._data);
	return result;
}

template <typename T>
T vector<T>::dotProduct(vector const & v) const{
	if(_count!=v._count) throw 0;

	return pxx::core::VDotV(_count,_data,v._data);
}

template <typename T>
vector<T> vector<T>::muls(T d) const{
	vector result(_count);
	pxx::core::VMulS(_count,_data,d,result._data);
	return result;
}

}

template <typename T>
pxx::vector<T> operator*(T d, pxx::vector<T> const & v){
	return v.muls(d);
}


#endif /* ROW_H_ */
